package ch.coredump.tagcloud.data.appstate;

import java.io.File;

import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.RadioButton;
import javafx.scene.control.TextField;
import javafx.scene.control.Toggle;
import javafx.scene.control.ToggleGroup;
import javafx.scene.control.Tooltip;
import javafx.scene.effect.Bloom;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.scene.text.TextAlignment;
import javafx.stage.DirectoryChooser;
import javafx.stage.DirectoryChooserBuilder;
import javafx.stage.FileChooser;
import javafx.stage.FileChooser.ExtensionFilter;
import javafx.stage.FileChooserBuilder;
import ch.coredump.tagcloud.CloudConsts;
import ch.coredump.tagcloud.CloudSettings;
import ch.coredump.tagcloud.data.DataProviderManager;
import ch.coredump.tagcloud.data.FileDataProvider;
import ch.coredump.tagcloud.scene.DisplayType;

/**
 * AppState for the menu.<br>
 * The user can choose the file(s) to parse and generate the TagCloud<br>
 */
public class AppStateMenu extends AbstractAppState {

	private GridPane root;
	private FileChooser filechooser;
	private DirectoryChooser directoryChooser;
	private FileDataProvider dataProvider;
	private TextField txtMaxWords;
	private TextField txtFileName;
	private static CloudSettings settings = CloudSettings.instance();
	private ToggleGroup displayOption;
	private TextField txtMinWordLength;
	private TextField txtFileExtension;
	private TextField txtMinFontSize;
	private TextField txtMaxFontSize;

	public AppStateMenu(AppStateManager manager) {
		super(manager);
	}

	@Override
	public Scene createScene() {
		root = new GridPane();
		Scene scene = new Scene(root, CloudConsts.SCREEN_X,
				CloudConsts.SCREEN_Y, true);
		scene.setFill(Color.WHITE);

		createUI();

		return scene;
	}

	/**
	 * create menu controls
	 */
	private void createUI() {
		createSettingsPane();
		cerateButtonPanel();
	}

	private void cerateButtonPanel() {
		GridPane pane = new GridPane();
		pane.setTranslateX(CloudConsts.SCREEN_X / 3);
		pane.setTranslateY(CloudConsts.SCREEN_Y - 200);
		pane.setHgap(30);
		pane.setVgap(30);

		root.getChildren().add(pane);

		// generate cloud button
		{
			Button button = createButton("Generate TagCloud");
			GridPane.setHgrow(button, Priority.ALWAYS);
			button.setFont(new Font(25));
			button.setOnAction(new EventHandler<ActionEvent>() {
				@Override
				public void handle(ActionEvent event) {
					saveSettings();
					// parse file
					File file = new File(txtFileName.getText());
					dataProvider.reset();
					dataProvider.parse(file);
					Toggle t = displayOption.getSelectedToggle();
					DisplayType type = (DisplayType) t.getUserData();
					settings.setDisplayType(type);
					manager.switchTo(AppStates.MAIN);
				}
			});
			GridPane.setHgrow(button, Priority.ALWAYS);
			pane.getChildren().add(button);
		}

		pane.setTranslateX(pane.getTranslateX()
				- pane.getLayoutBounds().getWidth());
	}

	private void saveSettings() {
		{
			Integer value = 0;
			try {
				value = Integer.valueOf(txtMaxWords.getText());
			} catch (NumberFormatException e) {
				log.warning(txtMaxWords.getText() + " is not a number");
				txtMaxWords
						.setText(String.valueOf(CloudSettings.DEF_MAX_WORDS));
			}

			settings.setMaxWordsOndisplay(value);
			settings.setFileExtension(txtFileExtension.getText());
		}

		{
			String text = txtMinWordLength.getText();
			Integer minLength = null;
			try {
				minLength = Integer.valueOf(text);
			} catch (Exception e) {
				log.warning(text + " is not a number");
				minLength = 3;
			}
			settings.setMinWordLength(minLength);
		}

		{
			String text = txtMinFontSize.getText();
			Integer value = null;
			try {
				value = Integer.valueOf(text);
			} catch (Exception e) {
				log.warning(text + " is not a number");
				value = 3;
			}
			settings.setMinFontSize(value);
		}

		{
			String text = txtMaxFontSize.getText();
			Integer value = null;
			try {
				value = Integer.valueOf(text);
			} catch (Exception e) {
				log.warning(text + " is not a number");
				value = 3;
			}
			settings.setMaxFontSize(value);
		}
	}

	private void createSettingsPane() {
		GridPane pane = new GridPane();
		pane.setTranslateX(50);
		pane.setTranslateY(50);
		pane.setHgap(10);
		pane.setVgap(10);

		root.getChildren().add(pane);

		createText(pane, "Settings", 20);

		int x = 0, y = 0;

		x = 0;
		y++;
		;
		txtMaxWords = createTextField(pane, "max number of Words",
				"max number of tags to display", "100", 4, x, y);
		x = 0;
		y++;
		;
		txtMinWordLength = createTextField(pane, "min word length",
				"words shorter than this will be ignored", "3", 4, x, y);

		x = 0;
		y++;
		txtFileName = createTextField(
				pane,
				"file or folder",
				"relative or absolute path to a file or folder containing files to parse",
				"data/testdata.txt", 20, x, y);
		x = 2;

		// file chooser
		{
			Button button = new Button("Choose File");
			GridPane.setHgrow(button, Priority.ALWAYS);
			GridPane.setColumnIndex(button, x);
			GridPane.setRowIndex(button, y);

			button.setOnAction(new EventHandler<ActionEvent>() {
				@Override
				public void handle(ActionEvent event) {
					settings.setFileExtension(txtFileExtension.getText());
					filechooser.getExtensionFilters().setAll(
							new ExtensionFilter("*."
									+ settings.getFileExtension(), "*."
									+ settings.getFileExtension()),
							new ExtensionFilter("all", "*"));
					File file = filechooser.showOpenDialog(manager.getStage());
					if (file != null) {
						txtFileName.setText(file.getPath());
					}

				}
			});
			pane.getChildren().add(button);
		}
		x++;

		// folder chooser
		{
			Button button = new Button("Choose Folder");
			GridPane.setHgrow(button, Priority.ALWAYS);
			GridPane.setColumnIndex(button, x);
			GridPane.setRowIndex(button, y);

			button.setOnAction(new EventHandler<ActionEvent>() {
				@Override
				public void handle(ActionEvent event) {
					File file = directoryChooser.showDialog(getScene()
							.getWindow());
					if (file != null) {
						txtFileName.setText(file.getPath());
					}
				}
			});
			pane.getChildren().add(button);
		}

		x = 0;
		y++;
		;
		txtFileExtension = createTextField(pane, "file extension",
				"extension of files to parse, others will be ignored", "txt",
				4, x, y);

		x = 0;
		y++;
		displayOption = createDisplayOption(pane, "tag display order:",
				"order in which the tags will be displayed", 4, x, y);

		y++;
		txtMinFontSize = createTextField(pane, "min font size", null,
				String.valueOf(CloudConsts.FONT_MIN), 4, x, y);

		y++;
		txtMaxFontSize = createTextField(pane, "max font size", null,
				String.valueOf(CloudConsts.FONT_MAX), 4, x, y);

	}

	private ToggleGroup createDisplayOption(GridPane pane, String string,
			String tooltip, int i, int x, int y) {
		final ToggleGroup group = new ToggleGroup();
		HBox buttonBox = new HBox(20);
		GridPane.setConstraints(buttonBox, x + 1, y);
		pane.getChildren().add(buttonBox);

		{
			RadioButton radioButton = new RadioButton("Random");
			buttonBox.getChildren().add(radioButton);
			radioButton.setToggleGroup(group);
			radioButton.setUserData(DisplayType.RANDOM);
			group.selectToggle(radioButton);
			radioButton.setTooltip(new Tooltip(tooltip));
		}
		{
			RadioButton radioButton = new RadioButton("Alphabethical");
			buttonBox.getChildren().add(radioButton);
			radioButton.setUserData(DisplayType.ALPHA);
			radioButton.setToggleGroup(group);
			radioButton.setTooltip(new Tooltip(tooltip));
		}
		{
			RadioButton radioButton = new RadioButton("Word count");
			buttonBox.getChildren().add(radioButton);
			radioButton.setUserData(DisplayType.WEIGHT);
			radioButton.setToggleGroup(group);
			radioButton.setTooltip(new Tooltip(tooltip));
		}

		Label label = new Label(string);
		label.setFont(new Font(CloudConsts.DEF_FONT_SIZE));
		pane.getChildren().add(label);
		GridPane.setConstraints(label, x, y);

		return group;
	}

	private TextField createTextField(Pane parent, String labelText,
			String tooltip, String defaultText, int cols, int x, int y) {
		TextField tf = new TextField(defaultText);
		tf.setPrefColumnCount(cols);
		parent.getChildren().add(tf);
		tf.setTooltip(new Tooltip(tooltip));
		GridPane.setConstraints(tf, x + 1, y);

		Label label = new Label(labelText);
		label.setFont(new Font(CloudConsts.DEF_FONT_SIZE));
		parent.getChildren().add(label);
		label.setLabelFor(tf);
		GridPane.setConstraints(label, x, y);
		return tf;
	}

	private Button createButton(String label) {
		Button button = new Button(label);
		GridPane.setColumnIndex(button, 1);
		GridPane.setRowIndex(button, 2);
		return button;
	}

	private Text createText(Pane parent, String text, int size) {
		Text t = new Text(text);
		t.setTextAlignment(TextAlignment.CENTER);
		t.setFill(Color.BLACK);
		t.setFont(Font.font("Arial", size));

		parent.getChildren().add(t);

		Bloom bloom = new Bloom();
		bloom.setThreshold(0.5);
		t.setEffect(bloom);

		return t;
	}

	@Override
	public void activate() {
		scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
			public void handle(KeyEvent event) {
				KeyCode code = event.getCode();
				if (code == KeyCode.ESCAPE) {
					manager.switchTo(AppStates.EXIT);
				}
			};
		});
	}

	@Override
	public void exit() {
		scene.setOnKeyPressed(null);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void init() {
		dataProvider = DataProviderManager.getInstance().getDataProvider();

		// create the file chooser
		FileChooserBuilder file = FileChooserBuilder.create();

		file.title("Choose File");
		String currentDir = System.getProperties().getProperty("user.dir");
		file.initialDirectory(new File(currentDir));
		filechooser = file.build();

		DirectoryChooserBuilder builder = DirectoryChooserBuilder.create();
		builder.title("Choose Directory");
		builder.initialDirectory(new File(currentDir));
		directoryChooser = builder.build();
	}
}
